﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Common.Network.Helpers
{
    public class PacketParser
    {
        public static string GetString(ref byte[] data, ref int offset)
        {
            byte[] lengthBytes = new byte[] { data[offset + 1], data[offset] };
            short strLength = BitConverter.ToInt16(lengthBytes, 0);
            offset += 2;
            string str = Encoding.BigEndianUnicode.GetString(data, offset, strLength*2);
            offset += strLength;
            return str;
        }
        public static string GetString(ref byte[] data, ref int offset, Encoding encoding)
        {
            byte[] lengthBytes = new byte[]{data[offset+1],data[offset]};
            short strLength = BitConverter.ToInt16(lengthBytes, 0);
            offset += 2;
            string str = encoding.GetString(data, offset, strLength);
            offset += strLength;
            return str;
        }

        public static long GetLong(ref byte[] data, ref int offset)
        {
            byte[] lengthBytes = new byte[] { data[offset + 7], data[offset + 6], data[offset + 5], data[offset + 4], data[offset + 3], data[offset + 2], data[offset + 1], data[offset] };
            long result = BitConverter.ToInt64(lengthBytes, 0);
            offset += 8;
            return result;
        }
        public static ulong GetULong(ref byte[] data, ref int offset)
        {
            byte[] lengthBytes = new byte[] { data[offset + 7], data[offset + 6], data[offset + 5], data[offset + 4], data[offset + 3], data[offset + 2], data[offset + 1], data[offset] };
            ulong result = BitConverter.ToUInt64(lengthBytes, 0);
            offset += 8;
            return result;
        }
        public static int GetInt(ref byte[] data, ref int offset)
        {
            byte[] lengthBytes = new byte[] { data[offset + 3], data[offset + 2], data[offset + 1], data[offset] };
            int result = BitConverter.ToInt32(lengthBytes, 0);
            offset += 4;
            return result;
        }
        public static uint GetUInt(ref byte[] data, ref int offset)
        {
            byte[] lengthBytes = new byte[] { data[offset + 3], data[offset + 2], data[offset + 1], data[offset] };
            uint result = BitConverter.ToUInt32(lengthBytes, 0);
            offset += 4;
            return result;
        }
        public static short GetShort(ref byte[] data, ref int offset)
        {
            byte[] lengthBytes = new byte[] { data[offset + 1], data[offset] };
            short result = BitConverter.ToInt16(lengthBytes, 0);
            offset += 2;
            return result;
        }
        public static ushort GetUShort(ref byte[] data, ref int offset)
        {
            byte[] lengthBytes = new byte[] { data[offset + 1], data[offset] };
            ushort result = BitConverter.ToUInt16(lengthBytes, 0);
            offset += 2;
            return result;
        }
        public static byte GetByte(ref byte[] data, ref int offset)
        {
            byte result = data[offset++];
            return result;
        }
        public static bool GetBool(ref byte[] data, ref int offset)
        {
            bool result = data[offset++]==1;
            return result;
        }

        public static float GetFloat(ref byte[] data, ref int offset)
        {
            byte[] lengthBytes = new byte[] { data[offset + 3], data[offset + 2], data[offset + 1], data[offset] };
            float result = BitConverter.ToSingle(lengthBytes, 0);
            offset += 4;
            return result;
        }
        public static double GetDouble(ref byte[] data, ref int offset)
        {
            byte[] lengthBytes = new byte[] { data[offset + 7], data[offset + 6], data[offset + 5], data[offset + 4], data[offset + 3], data[offset + 2], data[offset + 1], data[offset] };
            double result = BitConverter.ToDouble(lengthBytes, 0);
            offset += 8;
            return result;
        }

        public static void PutString(ref byte[] data, string input)
        {
            byte[] strBytes = Encoding.BigEndianUnicode.GetBytes(input);
            byte[] lengthBytes = BitConverter.GetBytes((short)strBytes.Length/2);
            byte byte1 = lengthBytes[0];
            lengthBytes[0] = lengthBytes[1];
            lengthBytes[1] = byte1;
            int oldDataLength = data.Length;
            byte[] newData = new byte[data.Length+strBytes.Length+2];
            Array.Copy(data,0,newData,0,data.Length);
            Array.Copy(lengthBytes, 0, newData, oldDataLength, 2);
            Array.Copy(strBytes, 0, newData, oldDataLength+2, strBytes.Length);
            data = newData;
        }
        public static void PutString(ref byte[] data, string input, Encoding encoding)
        {
            byte[] strBytes = encoding.GetBytes(input);
            short length = encoding == Encoding.Unicode ? (short) (strBytes.Length/2) : (short) strBytes.Length;
            byte[] lengthBytes = BitConverter.GetBytes(length);
            byte byte1 = lengthBytes[0];
            lengthBytes[0] = lengthBytes[1];
            lengthBytes[1] = byte1;
            int oldDataLength = data.Length;
            byte[] newData = new byte[data.Length + strBytes.Length + 2];
            Array.Copy(data, 0, newData, 0, data.Length);
            Array.Copy(lengthBytes, 0, newData, oldDataLength, 2);
            Array.Copy(strBytes, 0, newData, oldDataLength + 2, strBytes.Length);
            data = newData;
        }

        public static void PutULong(ref byte[] data, ulong input)
        {
            byte[] inputBytes = BitConverter.GetBytes(input);
            byte[] newData = new byte[data.Length + 8];
            byte b1 = inputBytes[0];
            byte b2 = inputBytes[1];
            byte b3 = inputBytes[2];
            byte b4 = inputBytes[3];
            byte b5 = inputBytes[4];
            byte b6 = inputBytes[5];
            byte b7 = inputBytes[6];
            byte b8 = inputBytes[7];
            inputBytes[0] = b8;
            inputBytes[1] = b7;
            inputBytes[2] = b6;
            inputBytes[3] = b5;
            inputBytes[4] = b4;
            inputBytes[5] = b3;
            inputBytes[6] = b2;
            inputBytes[7] = b1;
            int oldDataLength = data.Length;
            Array.Copy(data, 0, newData, 0, data.Length);
            Array.Copy(inputBytes, 0, newData, oldDataLength, 8);
            data = newData;
        }
        public static void PutLong(ref byte[] data, long input)
        {
            byte[] inputBytes = BitConverter.GetBytes(input);
            byte[] newData = new byte[data.Length + 8];
            byte b1 = inputBytes[0];
            byte b2 = inputBytes[1];
            byte b3 = inputBytes[2];
            byte b4 = inputBytes[3];
            byte b5 = inputBytes[4];
            byte b6 = inputBytes[5];
            byte b7 = inputBytes[6];
            byte b8 = inputBytes[7];
            inputBytes[0] = b8;
            inputBytes[1] = b7;
            inputBytes[2] = b6;
            inputBytes[3] = b5;
            inputBytes[4] = b4;
            inputBytes[5] = b3;
            inputBytes[6] = b2;
            inputBytes[7] = b1;
            int oldDataLength = data.Length;
            Array.Copy(data, 0, newData, 0, data.Length);
            Array.Copy(inputBytes, 0, newData, oldDataLength, 8);
            data = newData;
        }
        public static void PutUInt(ref byte[] data, uint input)
        {
            byte[] inputBytes = BitConverter.GetBytes(input);
            byte[] newData = new byte[data.Length + 4];
            byte b1 = inputBytes[0];
            byte b2 = inputBytes[1];
            byte b3 = inputBytes[2];
            byte b4 = inputBytes[3];
            inputBytes[0] = b4;
            inputBytes[1] = b3;
            inputBytes[2] = b2;
            inputBytes[3] = b1;
            int oldDataLength = data.Length;
            Array.Copy(data, 0, newData, 0, data.Length);
            Array.Copy(inputBytes, 0, newData, oldDataLength, 4);
            data = newData;
        }
        public static void PutInt(ref byte[] data, int input)
        {
            byte[] inputBytes = BitConverter.GetBytes(input);
            byte[] newData = new byte[data.Length + 4];
            byte b1 = inputBytes[0];
            byte b2 = inputBytes[1];
            byte b3 = inputBytes[2];
            byte b4 = inputBytes[3];
            inputBytes[0] = b4;
            inputBytes[1] = b3;
            inputBytes[2] = b2;
            inputBytes[3] = b1;
            int oldDataLength = data.Length;
            Array.Copy(data, 0, newData, 0, data.Length);
            Array.Copy(inputBytes, 0, newData, oldDataLength, 4);
            data = newData;
        }
        public static void PutUShort(ref byte[] data, ushort input)
        {
            byte[] inputBytes = BitConverter.GetBytes(input);
            byte[] newData = new byte[data.Length + 2];
            byte b1 = inputBytes[0];
            byte b2 = inputBytes[1];
            inputBytes[0] = b2;
            inputBytes[1] = b1;
            int oldDataLength = data.Length;
            Array.Copy(data, 0, newData, 0, data.Length);
            Array.Copy(inputBytes, 0, newData, oldDataLength, 2);
            data = newData;
        }
        public static void PutShort(ref byte[] data, short input)
        {
            byte[] inputBytes = BitConverter.GetBytes(input);
            byte[] newData = new byte[data.Length + 2];
            byte b1 = inputBytes[0];
            byte b2 = inputBytes[1];
            inputBytes[0] = b2;
            inputBytes[1] = b1;
            int oldDataLength = data.Length;
            Array.Copy(data, 0, newData, 0, data.Length);
            Array.Copy(inputBytes, 0, newData, oldDataLength, 2);
            data = newData;
        }
        public static void PutByte(ref byte[] data, byte input)
        {
            byte[] newData = new byte[data.Length + 1];
            int oldDataLength = data.Length;
            Array.Copy(data, 0, newData, 0, data.Length);
            Array.Copy(new byte[]{input}, 0, newData, oldDataLength, 1);
            data = newData;
        }
        public static void PutBool(ref byte[] data, bool input)
        {
            byte[] newData = new byte[data.Length + 1];
            int oldDataLength = data.Length;
            Array.Copy(data, 0, newData, 0, data.Length);
            Array.Copy(new byte[]{input?(byte)1:(byte)0}, 0, newData, oldDataLength, 1);
            data = newData;
        }

        public static void PutDouble(ref byte[] data, double input)
        {
            byte[] inputBytes = BitConverter.GetBytes(input);
            byte[] newData = new byte[data.Length + 8];
            byte b1 = inputBytes[0];
            byte b2 = inputBytes[1];
            byte b3 = inputBytes[2];
            byte b4 = inputBytes[3];
            byte b5 = inputBytes[4];
            byte b6 = inputBytes[5];
            byte b7 = inputBytes[6];
            byte b8 = inputBytes[7];
            inputBytes[0] = b8;
            inputBytes[1] = b7;
            inputBytes[2] = b6;
            inputBytes[3] = b5;
            inputBytes[4] = b4;
            inputBytes[5] = b3;
            inputBytes[6] = b2;
            inputBytes[7] = b1;
            int oldDataLength = data.Length;
            Array.Copy(data, 0, newData, 0, data.Length);
            Array.Copy(inputBytes, 0, newData, oldDataLength, 8);
            data = newData;
        }
        public static void PutFloat(ref byte[] data, float input)
        {
            byte[] inputBytes = BitConverter.GetBytes(input);
            byte[] newData = new byte[data.Length + 4];
            byte b1 = inputBytes[0];
            byte b2 = inputBytes[1];
            byte b3 = inputBytes[2];
            byte b4 = inputBytes[3];
            inputBytes[0] = b4;
            inputBytes[1] = b3;
            inputBytes[2] = b2;
            inputBytes[3] = b1;
            int oldDataLength = data.Length;
            Array.Copy(data, 0, newData, 0, data.Length);
            Array.Copy(inputBytes, 0, newData, oldDataLength, 4);
            data = newData;
        }
    }
}
